/*
 * PCCWBaseException.java
 *
 */

package com.inibb.app.exception;

import java.io.PrintWriter;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author Jason Tam
 */
public class PCCWBaseException extends java.lang.Exception implements
		Serializable {

	public static final String CODE_UNKNOWN = "UKWN";

	public static final String CODE_GENERAL = "GENL";

	public static final String CODE_INIT = "INIT";

	public static final String CODE_RUNTIME = "RUNT";

	public static final String CODE_DESTORY = "DESY";

	public static final String CODE_FATAL = "FATL";

	public static final String NEW_LINE = System.getProperty("line.separator",
			"\n");

	private String exCode;

	private String msgID;

	private Throwable nestedException;

	private List<Exception> exStack = new ArrayList<Exception>();

	private String subCode = "";

	private String subCodeDescription = "";

	/** Creates a new instance of PCCWBaseException */
	public PCCWBaseException(String code, String message) {
		this(code, message, null);
	}

	public PCCWBaseException(String code, String message, Throwable root) {
		super((message == null ? "" : message), root);
		exCode = (code == null ? "" : code);
		if (root instanceof PCCWBaseException) {
			append((PCCWBaseException) root);
		} else {
			nestedException = root;
		}
		exStack.add(this);
	}

	public String getCode() {
		return exCode;
	}

	public void setSubCode(String s) {
		subCode = (s == null ? "" : s);
	}

	public String getSubCode() {
		return subCode;
	}

	public void setSubCodeDescription(String s) {
		subCodeDescription = (s == null ? "" : s);
	}

	public String getSubCodeDescription() {
		return subCodeDescription;
	}

	public Throwable getNestedException() {
		return nestedException;
	}

	public String getMessageID() {
		return msgID;
	}

	public PCCWBaseException getRootException() {
		if (exStack.size() > 0) {
			return ((PCCWBaseException) exStack.get(0));
		} else {
			return this;
		}
	}

	public boolean isRoot() {
		return (exStack.size() == 1);
	}

	public PCCWBaseException[] getExceptionStack() {
		return exStack
				.toArray(new PCCWBaseException[] {});
	}

	public String getFullStackTrace() {
		java.io.StringWriter swr = new java.io.StringWriter();
		printFullStackTrace(swr);
		return swr.toString();
	}

	public void printFullStackTrace() {
		printFullStackTrace(new java.io.OutputStreamWriter(System.err));
	}

	public void printFullStackTrace(java.io.Writer writer) {
		PCCWBaseException[] exStack = getExceptionStack();
		try {
			writer.write("PCCWBaseException Stack:" + NEW_LINE);
			writer.write("  (top ) ");

			for (int i = exStack.length - 1; i >= 0; i--) {

				if (i >= 1) {
					writer.write(exStack[i].toString(false) + NEW_LINE);
					writer.write("  (with) ");
				} else {
					Throwable e = exStack[i].getNestedException();

					if (e != null) {
						writer.write(exStack[i].toString(false) + NEW_LINE);
						writer.write("  (root) ");
					} else {
						e = exStack[i];
					}

					if (e instanceof SQLException) {
						writer.write(extractSQLException(e) + NEW_LINE);
						writer.write("         ");
					}
					/*
					 * if (e instanceof JMSException) {
					 * writer.write(extractJMSException(e) + NEW_LINE);
					 * writer.write("         "); }
					 */

					e.printStackTrace(new PrintWriter(writer));
				}
			}
			writer.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public String toString() {
		return toString(true);
	}

	private String toString(boolean isFullMessage) {
		String s = this.getClass().getName() + " (Code=" + getCode() + "): "
				+ getMessage();
		if (isFullMessage) {
			if (!isRoot()) {
				PCCWBaseException root = getRootException();
				s += "; Root Exception: " + root;
			} else if (nestedException != null) {
				if (nestedException instanceof SQLException) {
					s += "; Nested SQLException: "
							+ extractSQLException(nestedException);
				} else {
					s += "; Nested Exception: " + nestedException;
				}
			}
		}
		return s;
	}

	private String extractSQLException(Throwable e) {
		String s = "";
		if (e instanceof SQLException) {
			SQLException sqle = (SQLException) e;
			s += sqle;
			while ((sqle = sqle.getNextException()) != null) {
				s += " -NextException-> " + sqle;
			}
		}
		return s;
	}

	/*
	 * private String extractJMSException(Throwable e) { String s = "";
	 * Exception ex = null;
	 * 
	 * if (e instanceof JMSException) { JMSException jmse = (JMSException) e; s
	 * += jmse; ex = jmse.getLinkedException();
	 * 
	 * if (ex!=null) { java.io.StringWriter swr = new StringWriter();
	 * ex.printStackTrace(new PrintWriter(swr)); s+= " -LinkedException-> " +
	 * swr.toString(); } } return s; }
	 */
	private List<Exception> getExceptionStackVector() {
		return exStack;
	}

	private void append(PCCWBaseException e) {
		if (e != null) {
			exStack.addAll(e.getExceptionStackVector());
		}
	}
//
//	private static void method1() throws PCCWBaseException {
//		try {
//			SQLException sqle = new java.sql.SQLException(
//					"File input error!!!!!");
//			sqle.setNextException(new SQLException("DAO NestException"));
//			throw sqle;
//			// throw new PCCWBaseException("root", "testing roor");
//
//		} catch (Exception e) {
//			PCCWBaseException e1 = new PCCWBaseException("TEST001",
//					"Root Testing Error", e);
//			// PCCWBaseException e = new PCCWBaseException("TEST001",
//			// "Root Testing Error", new java.sql.SQLException(
//			// "Dummy SQL Exception found!"));
//			throw e1;
//		}
//	}
//
//	private static void method2() throws PCCWBaseException {
//		try {
//			method1();
//		} catch (PCCWBaseException e) {
//			// PCCWBaseException e1 = new PCCWBaseException("TEST002",
//			// "Testing Error2", e);
//			throw e;
//		}
//	}
//
//	private static void method3() throws PCCWBaseException {
//		try {
//			method2();
//		} catch (Exception e) {
//			PCCWBaseException e1 = new PCCWBaseException("TEST003",
//					"Testing Error3", e);
//			throw e1;
//		}
//	}
//
//	private static void method4() throws PCCWBaseException {
//		try {
//			method3();
//		} catch (Exception e) {
//			PCCWBaseException e1 = new PCCWBaseException("TEST004",
//					"Testing Error4", e);
//			throw e1;
//		}
//	}

//	public static void main(String[] args) {
//		try {
//			try {
//				method4();
//			} catch (Exception e) {
//				throw new PCCWBaseException("TEST005", "Testing Error5", e);
//			}
//		} catch (PCCWBaseException re) {
//			re.printFullStackTrace();
//			// System.err.println();
//			// System.err.println(re);
//		}
//	}
}